home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 October: Technology Seed / ADC Seed CD - October 1999.toast / FireWire / FireWire_2.1_SDK_DR3 / Source / OpenTransport / FWOTDriver / HWSpecific.c < prev    next >
Encoding:
Text File  |  1999-05-17  |  23.0 KB  |  718 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        HWSpecific.c
  3.  
  4.     Contains:    This file contains the routine(s) that are hardware specific for the
  5.                 DLPI.  Each vendor must supply code that works with their own
  6.                 card.
  7.                 
  8.     Written by:    
  9.  
  10.     Copyright:    © 1994, 1996-1997 by Apple Computer, Inc., all rights reserved.
  11.  
  12.     Change History (most recent first):
  13.  
  14.       <FW14>     3/14/97    ES        Changed specID to Apple's vendor unique ID of 0x00A040.
  15.       <FW13>     1/16/97    ES        Changed to invalidate CSRROMEntryID's before using and to
  16.                                     deallocate them when we're done.
  17.       <FW12>      1/9/97    ES        Took out some debugging stuff. Removed fixed address allocation.
  18.       <FW11>    12/27/96    ES        Changed a bunch of "FWDriver"s to "FWClient"s. Changed to
  19.                                     protocol driver.
  20.       <FW10>    12/16/96    ES        Changed to work with new read/write/lock request/complete
  21.                                     processing mechanism.
  22.        <FW9>     12/3/96    ES        Added kFWFixedAddress flag to FWAllocateAddressSpace.
  23.        <FW8>     9/27/96    ES        Changed to use set driver interface calls rather than driver
  24.                                     interface table.
  25.        <FW7>      9/3/96    ES        Added line to nil out reset notification proc in driver
  26.                                     interface table.
  27.        <FW6>     8/29/96    ES        Changed FWRegisterDriver to take driver interface proc table.
  28.        <FW5>     8/26/96    ES        Changed to new command object interface.
  29.        <FW4>      8/1/96    ES        Took out unused local variables.
  30.        <FW3>     4/17/96    ES        Changed call to FWRegisterDriver.
  31.        <FW2>     4/15/96    ES        Update for use with Driver Notification services. Call
  32.                                     FWRegisterDriver instead of OTFindPort to get fwDriverID.
  33.        <FW1>     3/27/96    ES        first checked in
  34.  
  35.     To Do:
  36. */
  37.  
  38. //-----------------------------------------------------------------------------------------
  39. //    Header files
  40. //-----------------------------------------------------------------------------------------
  41.  
  42. #include <OpenTptModule.h>                // Open Transport files
  43. #include <OpenTptDevLinks.h>
  44.  
  45. #include <Interrupts.h>                    // System files
  46. #include <PCI.h>
  47. #include <Kernel.h>
  48. #include <OSUtils.h>
  49. #include <DriverServices.h>
  50.  
  51. #include "DLPIRoutines.h"
  52. #include "HWSpecific.h"
  53. #include "EntryPoints.h"
  54. /*zzz*/
  55. static char  debugStr[256];
  56. /*zzz*/
  57.  
  58. static OSStatus    ABCVendorCreatePDriverUnitDirectory (
  59.     FWPDriverID                    fwPDriverID,
  60.     CSRROMEntryID                *pFWPDriverCSRROMUnitDirID);
  61.  
  62. void    ABCVendorTransmitQueuedPacket (void);
  63.  
  64. //-----------------------------------------------------------------------------------------
  65. // Global variable for the entire CFM
  66. //-----------------------------------------------------------------------------------------
  67.  
  68. extern    DLPIPrivateData *gDLPIPrivateData;        // Declared in EntryPoints.c
  69.  
  70. //-----------------------------------------------------------------------------------------
  71. //    Description:
  72. //        This routine enables our interrupts based on a parameter passed in.  Code should
  73. //        be added to this routine that enables the various interrupt bits on the card.
  74. //        The enable and disable routines are used by the queue routines to protect
  75. //        critical code sections.  Instead of masking all interrupts we just select
  76. //        the appropriate ones for our card.
  77. //
  78. //    Input:
  79. //        whichIntsOn - turn which interrupts on transmit, receive, or none
  80. //
  81. //    Output:
  82. //        NONE
  83. //
  84. //-----------------------------------------------------------------------------------------
  85. void ABCVendorEnableInterrupts(UInt16 whichIntsOn)
  86. {
  87.  
  88. switch (whichIntsOn)
  89.     {
  90.     case kTxInterrupts:
  91.         // turn on tx interrupts
  92.         gDLPIPrivateData->txInterruptsOn = 1;
  93.         break;
  94.     case kRxInterrupts:
  95.         // turn on rx interrupts
  96.         gDLPIPrivateData->rxInterruptsOn = 1;
  97.         break;
  98.     case kBothTxRxInterrupts:
  99.         // turn on both interrupts
  100.         gDLPIPrivateData->rxInterruptsOn = 1;
  101.         gDLPIPrivateData->txInterruptsOn = 1;
  102.         break;
  103.     default:
  104.         break;
  105.     }
  106.             
  107. }
  108.  
  109. //-----------------------------------------------------------------------------------------
  110. //    Description:
  111. //        This routine disables our interrupts based on a parameter passed in.Code should
  112. //        be added to this routine that disables the various interrupt bits on the card.
  113. //        The enable and disable routines are used by the queue routines to protect
  114. //        critical code sections.  Instead of masking all interrupts we just select
  115. //        the appropriate ones for our card.
  116. //
  117. //    Input:
  118. //        whichIntsOff - turn which interrupts off transmit, receive, or none
  119. //
  120. //    Output:
  121. //        NONE
  122. //
  123. //-----------------------------------------------------------------------------------------
  124. void ABCVendorDisableInterrupts(UInt16 whichIntsOff)
  125. {
  126.  
  127. switch (whichIntsOff)
  128.     {
  129.     case kTxInterrupts:
  130.         // turn off tx interrupts
  131.         gDLPIPrivateData->txInterruptsOn = 0;
  132.         break;
  133.     case kRxInterrupts:
  134.         // turn off rx interrupts
  135.         gDLPIPrivateData->rxInterruptsOn = 0;
  136.         break;
  137.     case kBothTxRxInterrupts:
  138.         // turn off both interrupts
  139.         gDLPIPrivateData->rxInterruptsOn = 0;
  140.         gDLPIPrivateData->txInterruptsOn = 0;
  141.         break;
  142.     default:
  143.         break;
  144.     }
  145.             
  146. }
  147.  
  148. //-----------------------------------------------------------------------------------------
  149. //    Description:
  150. //        This routine should determine if the card pointed to by theID can be used
  151. //        by this driver.  Before we can talk to the card, the card must be enabled.  To
  152. //        enable the card use the Expansion Manager calls to "set" the appropriate
  153. //        address space bit for your card.  
  154. //
  155. //        Always turn off the card after the test has been made.  Just because this routine
  156. //        is executed, it does not mean that the card is going to be used by the system.
  157. //        
  158. //    Input:
  159. //        theID - NameRegistry ID of our pci card
  160. //        resgisterSetAddress - base address of our pci card
  161. //
  162. //    Output:
  163. //        returns true, if driver can work with the card
  164. //        returns false, if driver cannot work with the card
  165. //
  166. //-----------------------------------------------------------------------------------------
  167. Boolean ABCVendorIsThisOurCard(RegEntryID *theID, UInt32 resgisterSetAddress)
  168. {
  169. return kTrue;
  170. }
  171.  
  172. //-----------------------------------------------------------------------------------------
  173. //    Description:
  174. //        This routine should set the physical address in the ethernet hw.  On initialization
  175. //        we may have read our physical address out of a EPROM, but now somebody is 
  176. //        explicitly telling us to change our address.  Update in globals.
  177. //
  178. //    Input:
  179. //        physicalAddress - multicast address (array of 6 bytes)
  180. //
  181. //    Output:
  182. //        returns no error
  183. //
  184. //-----------------------------------------------------------------------------------------
  185. SInt32 ABCVendorSetEthernetAddress(UInt8 *physicalAddress)
  186. {
  187.  
  188. /*zzz*/
  189.     DebugStr1 ((ConstStr255Param) "\pABCVendorSetEthernetAddress");
  190. /*zzz*/
  191. OTCopy48BitAddress(physicalAddress,&gDLPIPrivateData->ourEAddress);
  192.  
  193. return kOTNoError;
  194. }
  195.  
  196. //-----------------------------------------------------------------------------------------
  197. //    Description:
  198. //        This routine retrieves the factory ethernet address.  This is not the same
  199. //        as the current ethernet physical address (ourEAddress).
  200. //
  201. //    Input:
  202. //        addressArray - address to place the factory ethernet address bytes
  203. //
  204. //    Output:
  205. //        NONE
  206. //
  207. //-----------------------------------------------------------------------------------------
  208. void ABCVendorGetFactoryEthernetAddress(UInt8 *addressArray)
  209. {
  210. UInt32        *pAddress;
  211.  
  212. /*zzz*/
  213.     DebugStr1 ((ConstStr255Param) "\pABCVendorGetFactoryEthernetAddress");
  214. /*zzz*/
  215.     pAddress = (UInt32 *) addressArray;
  216.     *pAddress = (UInt32) gDLPIPrivateData;
  217.     addressArray[4] = 0;
  218.     addressArray[5] = 0;
  219. }
  220.  
  221. //-----------------------------------------------------------------------------------------
  222. //    Description:
  223. //        This routine enables the hardware to receive a new multicast address.  The
  224. //        address has already been verified that it is a multicast address.  Another
  225. //        check was made before this routine was called that this address is not a 
  226. //        duplicate.  All that needs to be done at this point is manipulate the hardware
  227. //        so that it will start receiving packets whose destination is the address.
  228. //
  229. //    Input:
  230. //        newMulticastAddr - multicast address (array of 6 bytes)
  231. //
  232. //    Output:
  233. //        returns no error
  234. //
  235. //-----------------------------------------------------------------------------------------
  236. SInt32 ABCVendorRegisterMulticast(UInt8 *newMulticastAddr)
  237. {
  238.  
  239. return kOTNoError;
  240. }
  241.  
  242. //-----------------------------------------------------------------------------------------
  243. //    Description:
  244. //        This routine manipulates the hardware in order to not receive the multicast
  245. //        address.  The address was check to see if it had been registered previously.
  246. //        All that needs to be done at this point is manipulate the hardware
  247. //        so that it will stop receiving packets whose destination is the address.
  248. //
  249. //    Input:
  250. //        oldMulticastAddr - multicast address (array of 6 bytes)
  251. //
  252. //    Output:
  253. //        returns no error
  254. //
  255. //-----------------------------------------------------------------------------------------
  256. SInt32 ABCVendorUnregisterMulticast(UInt8 *oldMulticastAddr)
  257. {
  258.  
  259. return kOTNoError;
  260. }
  261.  
  262. //-----------------------------------------------------------------------------------------
  263. //    Description:
  264. //        This routine communicates with the transmitter to send the packet described in 
  265. //        the message block thePacket.  If for some unknown reason you cannot send
  266. //        the packet then drop the packet on the floor.
  267. //
  268. //        Code in this routine demonstrates how to extract the packet data from the
  269. //        message.  This is just a sample, change to fit your hardware.  It is currently
  270. //        commented out since the dma memory ptr is not defined.
  271. //
  272. //    Input:
  273. //        packetSize - byte count of the packet
  274. //        thePacket - message block that describes the packet to transmit
  275. //
  276. //    Output:
  277. //        NONE
  278. //
  279. //-----------------------------------------------------------------------------------------
  280. void ABCVendorTransmitOnePacket(mblk_t *thePacket, UInt16 packetSize)
  281. {
  282. QHdrPtr    transmitPacketQueue = gDLPIPrivateData->transmitPacketQueue;
  283. DLPITransmitPacketCommandPtr    pDLPITransmitPacketCommand;
  284. Ptr        transmitBuffer, transmitBufferStorage;
  285. UInt32    copySize;
  286. Boolean    busy = true;
  287.  
  288. transmitBufferStorage = OTAllocMem (packetSize);
  289. transmitBuffer = transmitBufferStorage;
  290. if (transmitBuffer != NULL)
  291. {
  292.     while (thePacket)
  293.         {
  294.         copySize = thePacket->b_wptr - thePacket->b_rptr;
  295.     
  296.         bcopy((Ptr)thePacket->b_rptr, transmitBuffer, copySize);
  297.         
  298.         transmitBuffer += copySize;
  299.         
  300.         thePacket = thePacket->b_cont;
  301.         
  302.         }
  303.  
  304.     pDLPITransmitPacketCommand = OTAllocMem (sizeof (DLPITransmitPacketCommand));
  305.     if (pDLPITransmitPacketCommand != NULL)
  306.     {
  307.         if (TestAndSet (0, (UInt8 *) &(transmitPacketQueue->qFlags)))
  308.             busy = true;
  309.         else
  310.             busy = false;
  311.  
  312.         pDLPITransmitPacketCommand->transmitBuffer = transmitBufferStorage;
  313.         pDLPITransmitPacketCommand->packetSize = packetSize;
  314.         PBEnqueueLast ((QElemPtr) pDLPITransmitPacketCommand, transmitPacketQueue);
  315.     }
  316.     else
  317.     {
  318.         packetSize = 0;
  319.     }
  320. }
  321. else
  322. {
  323.     packetSize = 0;
  324. }
  325.  
  326. if (!busy)
  327.     ABCVendorTransmitQueuedPacket ();
  328.  
  329. }
  330.  
  331. void    ABCVendorTransmitQueuedPacket (void)
  332. {
  333. QHdrPtr    transmitPacketQueue = gDLPIPrivateData->transmitPacketQueue;
  334. DLPITransmitPacketCommandPtr    pDLPITransmitPacketCommand;
  335. FWCommandObjectID    asynchCommandObjectID;
  336. Ptr        transmitBuffer;
  337. UInt32    packetSize;
  338. UInt32    packetCount = 0;
  339.  
  340. pDLPITransmitPacketCommand = (DLPITransmitPacketCommandPtr) transmitPacketQueue->qHead;
  341. transmitBuffer = pDLPITransmitPacketCommand->transmitBuffer;
  342. packetSize = pDLPITransmitPacketCommand->packetSize;
  343. asynchCommandObjectID = gDLPIPrivateData->asynchCommandObjectID;
  344. if (asynchCommandObjectID == kInvalidFWCommandObjectID)
  345. {
  346.     ABCVendorTransmitCompletion (asynchCommandObjectID, noErr, (UInt32) pDLPITransmitPacketCommand);
  347.     return;
  348. }
  349.  
  350. if (packetSize > 0)
  351.     {
  352.     OTEnterInterrupt ();
  353.  
  354.     {
  355.         FWSetFWCommandCompletionProcData (asynchCommandObjectID,
  356.                                           (UInt32) pDLPITransmitPacketCommand);
  357.         FWSetCommonAsynchCommandParams (asynchCommandObjectID,
  358.                                         gDLPIPrivateData->targetAddress.addressHi,
  359.                                         gDLPIPrivateData->targetAddress.addressLo,
  360.                                         transmitBuffer,
  361.                                         packetSize);
  362.  
  363.         FWWrite (asynchCommandObjectID);
  364.     }
  365.  
  366.     OTLeaveInterrupt ();
  367.     }
  368. }
  369.  
  370. void ABCVendorTransmitCompletion(
  371.     FWCommandObjectID        fwCommandObjectID,
  372.     OSStatus                commandStatus,
  373.     UInt32                    completionProcData)
  374. {
  375. DLPITransmitPacketCommandPtr    pDLPITransmitPacketCommand;
  376. QHdrPtr    transmitPacketQueue = gDLPIPrivateData->transmitPacketQueue;
  377. Boolean    busy = true;
  378.  
  379. OTEnterInterrupt();        // open transport needs to be notified when entering an interrupt
  380.     pDLPITransmitPacketCommand = (DLPITransmitPacketCommandPtr) completionProcData;
  381.  
  382.     // for the transmitter
  383.     // is a packet waiting to be sent, then queue the deferred task
  384. if (gDLPIPrivateData->TxPacketQueue.qHead)
  385.     OTScheduleDeferredTask(gDLPIPrivateData->TxDeferredTaskCookie);
  386.  
  387. PBDequeue ((QElemPtr) pDLPITransmitPacketCommand, transmitPacketQueue);
  388.  
  389.     OTFreeMem ((Ptr) pDLPITransmitPacketCommand->transmitBuffer);
  390.     OTFreeMem ((Ptr) pDLPITransmitPacketCommand);
  391.  
  392. OTLeaveInterrupt();        // open transport needs to be notified when leaving an interrupt
  393.  
  394.     transmitPacketQueue->qFlags = 0;
  395.  
  396.     if (transmitPacketQueue->qHead != NULL)
  397.     {
  398.         if (TestAndSet (0, (UInt8 *) &(transmitPacketQueue->qFlags)))
  399.             busy = true;
  400.         else
  401.             busy = false;
  402.     }
  403.     
  404.     if (!busy)
  405.         ABCVendorTransmitQueuedPacket ();
  406.  
  407. }
  408.  
  409. //-----------------------------------------------------------------------------------------
  410. //    Description:
  411. //        This routine needs to check the transmitter hw to determine if it can send
  412. //        a packet with a size of packetSize.
  413. //
  414. //    Input:
  415. //        packetSize - byte count of the packet
  416. //
  417. //    Output:
  418. //        kOTNoError, if the transmitter hw can handle the packet
  419. //        nonzero, if the transmitter hw cannot handle the packet
  420. //
  421. //-----------------------------------------------------------------------------------------
  422. OSErr ABCVendorCheckTransmitterStatus(UInt16 packetSize)
  423. {
  424.  
  425. if (packetSize > kMaxTransmitSize)
  426.     return (-1);
  427. else
  428.     return kOTNoError;
  429. }
  430.  
  431. //-----------------------------------------------------------------------------------------
  432. //    Description:
  433. //        This routine first trys to allocate memory for our gDLPIPrivateData.The 
  434. //        hardware should then be initialized.  One of the things during the hw initialization
  435. //        that should be done is to read in our Ethernet address.
  436. //        The gDLPIPrivateData global is set in this routine.
  437. //
  438. //    Input:
  439. //        RegEntryID - NameRegistry ID for our PCI card
  440. //
  441. //    Output:
  442. //        gDLPIPrivateData, NULL if initialization was not successfull
  443. //        !NULL, if initialization was successfull
  444. //
  445. //-----------------------------------------------------------------------------------------
  446.  
  447. void ABCVendorInitialize(RegEntryID *theID)
  448. {
  449. FWPDriverProtocol            fwPDriverProtocolTable[1];
  450. CSRROMEntryID                csrROMUnitDirID;
  451. Ptr                            transmitBuffer;
  452. Ptr                            receiveBuffer;
  453. FWAddressSpaceID            fwAddressSpaceID;
  454.  
  455. /*zzz*/
  456.     DebugStr1 ((ConstStr255Param) "\pABCVendorInitialize");
  457. /*zzz*/
  458.     // allocate memory, do not use OT memory unless we need to, OT memory
  459.     //  allocation is interrupt safe so lets not waste it when we can use PoolAlocateResident.
  460.     // Thanks to a developer in Sweden for pointing this out!
  461. gDLPIPrivateData = (DLPIPrivateData *)PoolAllocateResident( sizeof(DLPIPrivateData),kTrue );
  462. if (gDLPIPrivateData == NULL)
  463.     return;
  464. transmitBuffer = PoolAllocateResident (kMaxTransmitSize, false);
  465. if (transmitBuffer == NULL)
  466. {
  467.     PoolDeallocate ((Ptr) gDLPIPrivateData);
  468.     gDLPIPrivateData = NULL;
  469.     return;
  470. }
  471. gDLPIPrivateData->transmitBuffer = transmitBuffer;
  472. receiveBuffer = PoolAllocateResident (kMaxTransmitSize, false);
  473. if (receiveBuffer == NULL)
  474. {
  475.     PoolDeallocate ((Ptr) transmitBuffer);
  476.     PoolDeallocate ((Ptr) gDLPIPrivateData);
  477.     gDLPIPrivateData = NULL;
  478.     return;
  479. }
  480. gDLPIPrivateData->receiveBuffer = receiveBuffer;
  481.  
  482. *(&gDLPIPrivateData->nodeEntryID) = *((RegEntryID *)theID);    // copy our reg node id
  483.  
  484. FWRegisterProtocolDriver (&gDLPIPrivateData->nodeEntryID, &(gDLPIPrivateData->fwPDriverID), 0);
  485. fwPDriverProtocolTable[0].specID = 0x00A040;//zzz use your own company ID here
  486. fwPDriverProtocolTable[0].swVersion = 'otn';
  487. FWSetPDriverProtocolTable (gDLPIPrivateData->fwPDriverID, &fwPDriverProtocolTable[0], 1);
  488. FWSetFWPDriverUnitAddedProc (gDLPIPrivateData->fwPDriverID, FWPDriverUnitAdded);
  489. FWSetFWPDriverUnitRemovedProc (gDLPIPrivateData->fwPDriverID, FWPDriverUnitRemoved);
  490. FWScanUnitsForFWPDriver (gDLPIPrivateData->fwPDriverID);
  491.  
  492. FWAllocateAddressSpace (&fwAddressSpaceID,
  493.                         (FWReferenceID) gDLPIPrivateData->fwPDriverID,
  494.                         &(gDLPIPrivateData->localAddress),
  495.                         kMaxTransmitSize,
  496.                         gDLPIPrivateData->receiveBuffer,
  497.                         kFWAddressWriteEnable | kFWAddressWriteCompleteNotify,
  498.                         (Ptr) gDLPIPrivateData);
  499.  
  500. ABCVendorCreatePDriverUnitDirectory (gDLPIPrivateData->fwPDriverID, &csrROMUnitDirID);
  501.  
  502. FWCSRROMInstantiate (gDLPIPrivateData->fwPDriverID);
  503.  
  504. FWSetFWClientWriteCompleteProc ((FWReferenceID) gDLPIPrivateData->fwPDriverID, FWClientWriteCompleteInterface);
  505.  
  506. PBQueueCreate (&(gDLPIPrivateData->transmitPacketQueue));
  507.  
  508. ABCVendorGetFactoryEthernetAddress(gDLPIPrivateData->ourEAddress);        
  509.  
  510.  
  511. // initialize hardware, remember to turn on the address map bit in the Config Command Register
  512. //    also if the card does dma then you need to turn on the dma (master) bit
  513.  
  514.  
  515. gDLPIPrivateData->TxDeferredTaskCookie = OTCreateDeferredTask(TxDTCallback,NULL);
  516. gDLPIPrivateData->RxDeferredTaskCookie = OTCreateDeferredTask(RxDTCallback,NULL);
  517.  
  518. }
  519.  
  520. ////////////////////////////////////////////////////////////////////////////////
  521. //
  522. // ABCVendorCreatePDriverUnitDirectory
  523. //
  524. //   This routine adds a Configuration ROM unit directory for the protocol driver.
  525. //zzz must do cleanup on error.
  526. //
  527.  
  528. static OSStatus    ABCVendorCreatePDriverUnitDirectory(
  529.     FWPDriverID                    fwPDriverID,
  530.     CSRROMEntryID                *pFWPDriverCSRROMUnitDirID)
  531. {
  532.     CSRROMEntryID                csrROMRootEntryID = kInvalidCSRROMEntryID,
  533.                                 csrROMUnitDirEntryID = kInvalidCSRROMEntryID,
  534.                                 csrROMEntryID = kInvalidCSRROMEntryID;
  535.     UInt32                        immediateEntry;
  536.     OSStatus                    status = noErr;
  537.  
  538.     // Get configuration ROM root directory.
  539.     status = FWCSRROMGetRootDirectory (fwPDriverID, &csrROMRootEntryID);
  540.  
  541.     // Create a new unit directory.
  542.     if (status == noErr)
  543.     {
  544.         status = FWCSRROMCreateEntry (csrROMRootEntryID,
  545.                                       &csrROMUnitDirEntryID,
  546.                                       kDirectoryCSRROMEntryType,
  547.                                       kCSRUnitDirectoryKey,
  548.                                       nil,
  549.                                       0);
  550.     }
  551.  
  552.     // Set unit's spec ID.
  553.     if (status == noErr)
  554.     {
  555.         immediateEntry = 0x00A040 << 8;//zzz use your own company ID here
  556.         status = FWCSRROMCreateEntry (csrROMUnitDirEntryID,
  557.                                       &csrROMEntryID,
  558.                                       kImmediateCSRROMEntryType,
  559.                                       kCSRUnitSpecIdKey,
  560.                                       (Ptr) &immediateEntry,
  561.                                       3);
  562.     }
  563.  
  564.     // Set unit's SW Version.
  565.     if (status == noErr)
  566.     {
  567.         immediateEntry = 'otn ';
  568.         status = FWCSRROMCreateEntry (csrROMUnitDirEntryID,
  569.                                       &csrROMEntryID,
  570.                                       kImmediateCSRROMEntryType,
  571.                                       kCSRUnitSwVersionKey,
  572.                                       (Ptr) &immediateEntry,
  573.                                       3);
  574.     }
  575.  
  576.     // Create unit dependent leaf.
  577.     if (status == noErr)
  578.     {
  579.         // Create the leaf containing our local write address.
  580.         status = FWCSRROMCreateEntry (csrROMUnitDirEntryID,
  581.                                       &csrROMEntryID,
  582.                                       kLeafCSRROMEntryType,
  583.                                       kCSRUnitDependentInfoKey,
  584.                                       (Ptr) &(gDLPIPrivateData->localAddress),
  585.                                       sizeof (FWAddress));
  586.     }
  587.  
  588.     // Clean up.
  589.     if (csrROMRootEntryID != kInvalidCSRROMEntryID)
  590.         FWCSRROMDisposeEntryID (csrROMRootEntryID);
  591.  
  592.     if (csrROMEntryID != kInvalidCSRROMEntryID)
  593.         FWCSRROMDisposeEntryID (csrROMEntryID);
  594.  
  595.     // Return unit directory ID.
  596.     if (status == noErr)
  597.         *pFWPDriverCSRROMUnitDirID = csrROMUnitDirEntryID;
  598.     else
  599.         *pFWPDriverCSRROMUnitDirID = kInvalidCSRROMEntryID;
  600.  
  601.     return (status);
  602. }
  603.  
  604.  
  605. //-----------------------------------------------------------------------------------------
  606. //    Description:
  607. //        This routine closes down the hardware.  The memory is also deallocated.  
  608. //        This routine undoes everything done in the initialize routine.
  609. //
  610. //    Input:
  611. //        NONE
  612. //
  613. //    Output:
  614. //        NONE
  615. //
  616. //-----------------------------------------------------------------------------------------
  617.  
  618. void ABCVendorClose(void)
  619. {
  620. mblk_t        *thePacket;
  621.  
  622. // turn off hardware
  623.  
  624. OTDestroyDeferredTask(gDLPIPrivateData->TxDeferredTaskCookie);
  625. OTDestroyDeferredTask(gDLPIPrivateData->RxDeferredTaskCookie);
  626.  
  627.  
  628.     // clear out the tx and rx dlpi private queues
  629. while ((thePacket = (mblk_t *) DequeueHead(&gDLPIPrivateData->RxPacketQueue, kNoInterrupts))
  630.     != NULL)
  631.     freemsg(thePacket);
  632.  
  633. while ((thePacket = (mblk_t *) DequeueHead(&gDLPIPrivateData->TxPacketQueue, kNoInterrupts)) 
  634.     != NULL)
  635.     freemsg(thePacket);
  636.  
  637.     // deallocate memory, must use same routine pair as the allocate
  638. PoolDeallocate(gDLPIPrivateData);
  639. gDLPIPrivateData = NULL;
  640.  
  641. }
  642.  
  643. //-----------------------------------------------------------------------------------------
  644. //    Description:
  645. //        This routine is the interrupt service routine for our card.  Do necessary 
  646. //        stuff in isr then defer for a later time the bulk of the work.  In the isr
  647. //        you need to notify Open Transport that we are in an isr.  The next step
  648. //        is to clear whatever hw bit you need to in order to deassert the interrupt line.
  649. //        
  650. //        For the transmitter...
  651. //            Since the transmitter isr section normally is called after a packet
  652. //            has been transmitted or some error occurs.  You need to cleanup anything
  653. //            related to the packet transmission (collect statistics, ...) and then
  654. //            check the TxPacketQueue to see if you have any packets waiting to
  655. //            be sent.  If there are packets then schedule the deferred task and when
  656. //            the callback occurs it will try to send any packet waiting on the queue.
  657. //
  658. //        For the receiver...
  659. //            If this section is called then you need to collect the packet and place
  660. //            it in a message block.  The message block can then be placed on the 
  661. //            RxPacketQueue.  The callback routine which is called after scheduling the
  662. //            deferred task will check the RxPacketQueue and send all packets on the
  663. //            queue to the appropriate stream.
  664. //
  665. //    Input:
  666. //        member - contains information about the pci interrupt member
  667. //        refCon - this value was passed in during the installation of the isr, since
  668. //                we have globals we do not need to use this
  669. //
  670. //    Output:
  671. //        return kIsrIsComplete always
  672. //
  673. //-----------------------------------------------------------------------------------------
  674.  
  675. InterruptMemberNumber ABCVendorISR(InterruptSetMember member, void *refCon, UInt32 theIntCount)
  676. {
  677.  
  678. OTEnterInterrupt();        // open transport needs to be notified when entering an interrupt
  679.  
  680. // clear the bit that caused the interrupt
  681.  
  682.     
  683.     // for the transmitter
  684.     // is a packet waiting to be sent, then queue the deferred task
  685. if (gDLPIPrivateData->TxPacketQueue.qHead)
  686.     OTScheduleDeferredTask(gDLPIPrivateData->TxDeferredTaskCookie);
  687.  
  688.  
  689.     // for the receiver check if anything has come in
  690.     // copy packet from hw into a message block then pass it on
  691.  
  692. //if ((thePacket = allocb(the packet size), BPRI_HI))
  693. //    {
  694.  
  695.         // copy packet into message block
  696. //    bcopy(DMAPtrToPacket, thePacket->b_rptr, the packet size);
  697. //    thePacket->b_wptr += the packet size;
  698. //    Return the dma memory to the dma engine.
  699.  
  700. // or you could use esballoc or OTAllocMsg which will use the DMAPtrToPacket
  701. // you will then get a callback when the client is finished with the dma memory
  702. // Keep in mind that packets could be returned via the callback out of order,
  703. // your dma hw might not be compatiable with this. 
  704. // 
  705.         // put packet on the queue so callback routine can dequeue it and
  706.         // pass it on to upper layers
  707. //    EnqueueElement(&gDLPIPrivateData->RxPacketQueue,(QElem *)thePacket,kNoInterrupts);
  708.     OTScheduleDeferredTask(gDLPIPrivateData->RxDeferredTaskCookie);
  709.     
  710. //    }
  711.  
  712.  
  713.  
  714. OTLeaveInterrupt();        // open transport needs to be notified when leaving an interrupt
  715.  
  716. return kIsrIsComplete;
  717. }
  718.